package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.exception.config.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.media.pojos.WmNews;
import com.heima.model.media.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description:
 * @Version: V1.0
 */
@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    WemediaFeign wemediaFeign;

    @Autowired
    ArticleFeign articleFeign;

    @Value("${file.oss.web-site}")
    private String webSite;


    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    GreenTextScan greenTextScan;

    /**
     * 自媒体文章自动审核方法-发布文章到APP端
     *
     * @param wmNewsId 文章id
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //0 参数校验
        if (wmNewsId == null) {
            log.error("****WemediaNewsAutoScanServiceImpl autoScanByMediaNewsId wmNewsId is null****");
            return;
        }

        //1 根据文章的id查询wmNews 数据
        WmNews wmNews = wemediaFeign.findById(wmNewsId);
        if (wmNews == null) {
            log.error("****wemediaFeign wmNews is null****");
            return;
        }

        //2 判断文章状态=4 （人工审核通过）且发布时间小于等于当前时间， 直接发布文章(保存三张表)
        short status = wmNews.getStatus().shortValue();
        long publishTime = wmNews.getPublishTime().getTime();
        if (status == WmNews.Status.ADMIN_SUCCESS.getCode()
                && publishTime <= System.currentTimeMillis()) {
            //保存数据
            publishArticle(wmNews);
            log.info("文章状态-人工审核通过，文章已发布，id:{}", wmNewsId);
            return;
        }
        //3 判断文章状态=8 （审核通过）且发布时间小于等于当前时间， 直接发布文章(保存三张表)
        if (status == WmNews.Status.SUCCESS.getCode()
                && publishTime <= System.currentTimeMillis()) {
            //保存数据
            publishArticle(wmNews);
            log.info("文章状态-审核通过，文章已发布，id:{}", wmNewsId);
            return;
        }

        //4 判断文章状态=1 (待审核状态)  根据审核的结果修改wmNews 状态\拒绝理由\app文章id
        if (status == WmNews.Status.SUBMIT.getCode()) {
            //4.0 解析文章content的文本和图片列表
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);

            //4.1 审核文章：自管理敏感词(文章标题，文章内容)
            boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
            if (!isSensitiveScan) return;


            //4.2 审核文章：阿里云内容反垃圾审核（block/review/pass） 文章内容
            boolean isTextScan = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
            if (!isTextScan) return;

            //4.3 审核文章：阿里云图片审核 文章图片（内容/封面）
            boolean isImageScan = handleImagesScan((List) contentAndImagesResult.get("images"), wmNews);
            if (!isImageScan) return;


            //5 审核通过，判断当前文章的发布时间大于当前时间，修改状态为8
            if (publishTime > System.currentTimeMillis()) {
                updateWmNews(wmNews, 8, "审核通过待发布");
            }

            // 6 保存文章，直接发布文章(保存三张表)，修改wmNews 状态9
            Long articleId = publishArticle(wmNews);


        }


    }

    @Autowired
    KafkaTemplate kafkaTemplate;

    /**
     * 远程保存 Article 三张表数据，
     *
     * @param wmNews
     * @return APP文章id返回
     */
    private Long publishArticle(WmNews wmNews) {

        // 远程调用保存APP文章 三张表数据 id 存到 result的data
        ResponseResult result = saveArticle(wmNews);

        if (result.getCode().intValue() != 0) {
            CustException.cust("保存APP文章失败");
        }

        wmNews.setArticleId((Long) result.getData());
        updateWmNews(wmNews, 9, "已发布");

        //6 生成文章对应的静态页面（发消息-异步） 消息体：发布成功后的文章ID
        Map<String, Long> map = new HashMap<>();
        map.put("articleId", wmNews.getArticleId());
        kafkaTemplate.send(NewsAutoScanConstants.GENERATE_PAGE_TOPIC, JSON.toJSONString(map));


        //TODO 7 同步索引库


        return wmNews.getArticleId();
    }


    @Autowired
    AdChannelMapper adChannelMapper;

    /**
     * 远程调用保存APP文章 三张表数据 id 存到 result的data
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {

        ArticleDto articleDto = new ArticleDto();

        // 属性拷贝
        BeanUtils.copyProperties(wmNews, articleDto);
        // 参数设置
//        articleDto.setId(null);
        articleDto.setId(wmNews.getArticleId());
        // 频道
        AdChannel channel = adChannelMapper.selectById(wmNews.getChannelId());
        if (channel != null && StringUtils.isNotBlank(channel.getName())) {
            articleDto.setChannelName(channel.getName());
            articleDto.setChannelId(channel.getId());
        }
        // 文章布局
        articleDto.setLayout(wmNews.getType());
        // 文章标记
        articleDto.setFlag(0);
        articleDto.setLikes(0);
        articleDto.setCollection(0);
        articleDto.setComment(0);
        articleDto.setViews(0);
        articleDto.setCreatedTime(new Date());
        articleDto.setSyncStatus(true);
        articleDto.setOrigin(true);

        // 文章作者
        // 查询自媒体账号是否是正常状态
        WmUser wmUser = wemediaFeign.findWmUserById(wmNews.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) {
            CustException.cust("当前自媒体用户已禁用，请联系运营人员确认");
        }
        // 尽量减少远程调用，缺少id***
        articleDto.setAuthorName(wmUser.getName());

        // 文章内容**
        articleDto.setContent(wmNews.getContent());

        // 远程调用 保存文章三张表数据, data 设置成功保存后的APP文章ID
        return articleFeign.saveArticle(articleDto);
    }

    /**
     * 4.3 审核文章：阿里云图片审核 文章图片（内容/封面）
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImagesScan(List<String> images, WmNews wmNews) {
        boolean flag = true;   // 成功

        try {
            Map map = greenImageScan.imageUrlScan(images);
            if (map.get("suggestion").equals("block")) { // 审核失败
                flag = false;
                log.error("阿里云审核：图片涉嫌违规");
                // CustException.cust("阿里云审核：图片涉嫌违规");
                updateWmNews(wmNews, 2, "阿里云审核-图片涉嫌违规");
            }

            if (map.get("suggestion").equals("review")) { // 需要人工审核
                flag = false;
                log.error("阿里云审核：需要人工审核");
                //CustException.cust("阿里云审核：需要人工审核");
                updateWmNews(wmNews, 3, "阿里云审核-需要人工审核");
            }

        } catch (Exception e) {
//            e.printStackTrace();
            flag = false;
            log.error("****图片审核失败，需要人工介入审核", e);
            updateWmNews(wmNews, 3, "阿里云审核失败-需要人工介入审核");
        }


        return flag;
    }

    /**
     * 4.2 审核文章：阿里云内容反垃圾审核（block/review/pass） 文章内容
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {

        boolean flag = true;   // 成功

        try {
            Map<String, String> map = greenTextScan.greenTextScan(content);

            if (map.get("suggestion").equals("block")) { // 审核失败
                flag = false;
                log.error("阿里云审核：文本中内容有敏感词汇");
                // CustException.cust("阿里云审核：文本中内容有敏感词汇");
                updateWmNews(wmNews, 2, "阿里云审核-文本中内容有敏感词汇");
            }

            if (map.get("suggestion").equals("review")) { // 需要人工审核
                flag = false;
                log.error("阿里云审核：需要人工审核");
                //CustException.cust("阿里云审核：需要人工审核");
                updateWmNews(wmNews, 3, "阿里云审核-需要人工审核");
            }

        } catch (Exception e) {
//            e.printStackTrace();
            flag = false;
            log.error("****阿里云内容反垃圾审核失败，需要人工审核", e);
            updateWmNews(wmNews, 3, "阿里云审核失败-需要人工介入审核");
        }

        return flag;
    }

    /**
     * 4.1 审核文章：自管理敏感词(文章标题，文章内容)
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {

        boolean flag = true;   // 成功

        // 查询所有的敏感词列表(数据库)
        List<String> words = adSensitiveMapper.findAllSensitive();
        SensitiveWordUtil.initMap(words);

        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);

        if (map.size() > 0) { // 包含敏感词
            flag = false;

            // 修改wm_news 状态为2，给理由
            log.error("****文章内容中包含敏感词：{}", map);
            updateWmNews(wmNews, 2, "文章中包含了敏感词:" + map);
        }

        return flag;
    }

    /**
     * 修改自媒体文章状态
     *
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, Integer status, String reason) {

        wmNews.setStatus(status);
        wmNews.setReason(reason);

        // article 文章id**  通过才有id
        ResponseResult result = wemediaFeign.updateWmNews(wmNews);
        if (result.getCode().intValue() != 0) {
            CustException.cust("修改自媒体文章状态失败");
        }
    }

    /**
     * 4.0 解析文章content的文本和图片列表
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();

        //1 获取文章内容并转换对象
        if (StringUtils.isBlank(content) || content.length() > 10000) {
            CustException.cust("文章内容不合法");
        }
        List<Map> contents = JSONArray.parseArray(content, Map.class);

        //2 解析内容文本
        // 文章标题
        String title = wmNews.getTitle();
        String contentText = contents.stream()
                .filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining("_"));
        String text = title + contentText;

        //3 解析文章内容图片(有前缀)
        List<String> images = contents.stream()
                .filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());
        //4 解析文章封面的图片 + 前缀
        if (wmNews.getImages().length() > 0) {
            images.addAll(
                    Stream.of(wmNews.getImages().split(","))
                            .map(url -> webSite + url)
                            .collect(Collectors.toList())
            );
        }

        //图片去重
        images = images.stream().distinct().collect(Collectors.toList());


        //5 封装结果并返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", text);
        resultMap.put("images", images);
        return resultMap;
    }
}
